using System;
using System.Collections;
using System.Collections.Generic;
using System.Html;
using System.Runtime.CompilerServices;
using System.Serialization;
using Awaiter;
using Nsb;
using Nsb.Classes;
using ThemeChain;
using WhirliGig.Classes;
using Yoshi.Classes;
using jQueryApi;

// ReSharper disable SuspiciousTypeConversion.Global
// ReSharper disable PossibleInvalidCastException

namespace WhirliGigEdit.Classes
{
    [IgnoreNamespace]
    public class Publish : Actor
    {
        private const string PgTop = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">";
        private const string PgEnd = "</html>";

        public static string PublishedIndex =
            @"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">" +
            @"<html xmlns=""http://www.w3.org/1999/xhtml"">" +
            @"<head>" +
            @"<title>website</title>" +
            @"<meta http-equiv=""refresh"" content=""0;url=@pagename@"">" +
            @"</head>" +
            @"<body>" +
            @"<" + @"script type=""text/javascript"">" +
            @"window.location.href = ""@pagename@"";" +
            @"<" + @"/script>" +
            @"</body>" +
            @"</html>";

        [PreserveName, PreserveCase]
        public static void PublishThisPageEv(jQueryEvent e)
        {
            CancelEvent(e);
            if (ThemeYoshi.CurrentPageName == ThemeYoshi.AdminPageName)
            {
                GlassOff();
                FlashWindow();
                return;
            }
            Await awx = new Await();
            if (!ThemeYoshi.CurrentPage.Visible)
                awx
                    .AddAw(new Ask().OkCancelAw, new Dictionary("Msg", String.Format("<small>This is a hidden page. If you publish it, then anyone will be able to view it at<br>{0}{1}</small>", ThemeYoshi.BaseUrl(), ThemeYoshi.PublishedUrl())))
                    .AddAw(RequireResultAw, true)
                    ;
            awx
                .AddDx(
                    delegate
                    {
                        //Storage.SetSession("PublishTime", (new Date()).GetTime()); // Not for single pages, only when ALL pages are published
                        Storage.SetLocal(ThemeYoshi.PublishingKey, true);
                        Storage.SetLocal(ThemeYoshi.CuratingKey, false);
                        Storage.SetLocal(ThemeYoshi.MetaBarKey, false);
                        //Storage.SetSession(ThemeYoshi.PageActionKey, String.Format("GigShow.PublishThisPagePx();")); });
                        ThemeBase.PageAction(delegate { GigShow.PublishThisPagePx(); });
                        Uri.BumpVersion();
                        ThemeYoshi.ReloadPage();
                    })
                .Commit();
        }

        [PreserveName, PreserveCase]
        public static void PublishThisPage()
        {
            new Await()
                .AddAw(PublishThisPageAw)
                .AddDx(
                    delegate
                    {
                        ThemeBase.Publishing = false;
                        Storage.RemoveLocal(ThemeYoshi.PublishingKey);
                        Storage.SetLocal(ThemeYoshi.CuratingKey, true);
                        ThemeBase.PageAction(delegate { Ask.Ok("current page is published"); });
                        ThemeYoshi.ReloadPage();
                    })
                .Commit()
                ;
        }

        /// <summary>
        /// Publish all the publishable pages
        /// </summary>
        /// <param name="e">event</param>
        [PreserveName, PreserveCase]
        public static void PublishEv(jQueryEvent e)
        {
            CancelEvent(e);
            Storage.SetSession("PublishTime", (new Date()).GetTime());
            Storage.SetLocal(ThemeYoshi.PublishingKey, true);
            Storage.SetLocal(ThemeYoshi.CuratingKey, false);
            Storage.SetLocal(ThemeYoshi.MetaBarKey, false);
            ThemeBase.PageAction(delegate { GigShow.PublishPagePx(-1); });
            Uri.BumpVersion();
            new Await()
                .AddAw(DeletePublishedFilesAw)
                .AddAw(SnapshotSoftwareAw)
                .AddFn(ThemeYoshi.ReloadPage)
                .Commit();
        }

        [PreserveName, PreserveCase]
        public static void PublishPage(int nxt)
        {
            int idx = 0;
            Await awx = new Await();
            foreach (KeyValuePair<string, PageD> pg in ThemeYoshi.Pages.pages)
            {
                if (idx == nxt)
                {
                    if (pg.Value.Visible)
                    {
                        Inform.Debug("Adding page idx={0}", idx);
                        awx.AddAw(PublishThisPageAw);
                    }
                    else
                        nxt++;
                }
                else if (idx == nxt + 1)
                {
                    if (pg.Value.Visible)
                    {
                        Inform.Debug("Queing page idx={0}", idx);
                        awx.AddDx(delegate { Storage.SetSession(ThemeBase.PageActionKey, String.Format("GigShow.PublishPagePx({0});", idx)); });
                        awx.AddDx(delegate { Script.Literal("Master.GoPage({0}, {1})", ThemeYoshi.CurrentPageClass, pg.Value.Name); });
                        awx.Commit();
                        return;
                    }
                    nxt++;
                }
                Inform.Debug("Skipping page idx={0}", idx);
                idx++;
            }
            awx.AddDx(
                delegate
                {
                    ThemeBase.Publishing = false;
                    Storage.RemoveLocal(ThemeYoshi.PublishingKey);
                    ThemeBase.PageAction(delegate
                                         {
                                             Storage.SetLocal(ThemeYoshi.CuratingKey, true);
                                             ThemeBase.PageAction(delegate { Ask.Ok("publish complete"); });
                                             ThemeYoshi.ReloadPage();
                                         });
                    Script.Literal("Master.GoPage({0}, {1})", ThemeYoshi.DefaultPageClass, ThemeYoshi.AdminPageName);
                });
            awx.Commit();
        }

        private static string RewriteLink(string href, jQueryObject el)
        {
            if (href == "javascript:;")
            {
                href = Strings.SafeFileName(el.GetHtml()) + ".html";
                return href;
            }
            if (href.IndexOf(ThemeYoshi.MasterPage) == 0)
            {
                href = (Uri.GetValue(href, "page") ?? ThemeYoshi.DefaultPageName) + ".html";
                el.RemoveAttr("target");
                return href;
            }
            return href;
        }

        [PreserveName, PreserveCase]
        private static void PublishThisPageAw(Await awp)
        {
            const string fnarg = "Publish.PublishThisPageAw";
            string pg = "\uFEFF"; // Byte order mark -- seems to be needed to keep unicode characters intact

            // Fix anchor hrefs
            jQueryObject links = jQuery.Select("a");
            links.Each(
                delegate(int i, Element domEl)
                {
                    jQueryObject t = jQuery.FromElement(domEl);
                    t.Attribute("href", RewriteLink(t.GetAttribute("href"), t));
                }
                );

            // Now get the page content
            string ct = jQuery.Select("html").GetHtml().Trim();

            // Embed the version
            ct = ct.ReplaceRegex((RegularExpression) Script.Literal(@"/\d+XvXvXv/"), Uri.MasterVersion + "XvXvXv");

            // Remove the extra library load
            ct = ct.ReplaceRegex((RegularExpression) Script.Literal(@"/<[s]cript\s+src="".*\/master.js\?_=\d+""\s*><\/[s]cript>/"), "");

            // Remove the extra css load <link rel="Stylesheet" type="text/css" href="master.css?_=' + version + '"/>
            ct = ct.ReplaceRegex((RegularExpression) Script.Literal(@"/<[l]ink\s+rel=""Stylesheet""\s+type=""text\/css""\s+href="".*\/master.css\?_=.+""\s*\/?>/"), "");

            // Fix links to reference back one level
            //ct = ct.Replace("href=\"Scripts/", "href=\"../Scripts/");
            //ct = ct.Replace("href=\"" + ThemeBase.DataPath + "/", "href=\"../" + ThemeBase.DataPath + "/");
            //ct = ct.Replace("src=\"Scripts/", "src=\"../Scripts/");
            //ct = ct.Replace("src=\"" + ThemeBase.DataPath + "/", "src=\"../" + ThemeBase.DataPath + "/");
            //ct = ct.ReplaceFirst("App/@MasterVersion.txt", "../App/@MasterVersion.txt");

            // Cut off the end </body> tag so more can be inserted
            ct = ct.Substr(0, ct.Length - "</body>".Length);

            // Initially hide the page content so it can be faded in
            ct += "\r\n<" + "script type='text/javascript'> jQuery('#PageGigs').hide();<" + "/script>";

            // Add StaticBuild.BuildAction()
            ct += "\r\n<" + "script type='text/javascript'> setTimeout( function() { try { StaticBuild.BuildAction('" + (ThemeYoshi.CurrentBuildAction ?? "") + "', '" + (ThemeYoshi.CurrentLoadLibs ?? "") + "', '" + (ThemeYoshi.CurrentLoadCss ?? "") + "'); } catch (ex) {}; }, 1 );<" + "/script>";

            // Insert object tilts
            Dictionary tilts = GigShow.GetTilts();
            if (tilts.Count > 0)
            {
                //ct = ct.ReplaceRegex((RegularExpression)Script.Literal(@"/-webkit-transform:[^;]+?;/g"), "");
                ct += "\r\n<" + "script type='text/javascript'> setTimeout( function() { try { StaticBuild.Tilt(" + Json.Stringify(tilts) + "); } catch (ex) {} }, 1 );<" + "/script>";
            }

            // Add StaticBuild.Finish()
            ct += "\r\n<" + "script type='text/javascript'> setTimeout( function() { try { StaticBuild.Finish(); } catch (ex) {} }, 1 );<" + "/script>";

            // Add back the </body> tag
            ct += "\r\n</body>";

            pg += PgTop;
            pg += ct;
            pg += PgEnd;

            StoreParams pm = new StoreParams();
            pm.partitionKey = "../pages";
            pm.rowKey = ThemeYoshi.CurrentPageName + ".html";
            pm.content = pg;

            Await awx = new Await()
                .AddAw(FileBlobBase.StoreBlobStringAw, (Dictionary) (object) pm)
                .AddDx(delegate { Inform.Event(fnarg, pm.rowKey); })
                ;

            if (ThemeYoshi.CurrentPageName == ThemeYoshi.DefaultPageName)
            {
                // Create the index.html page
                awx
                    .AddDx(
                        delegate
                        {
                            // Remove the <base> tag for the index page.
                            //pm.content = pm.content.ReplaceRegex((RegularExpression) Script.Literal(@"/\s*?<base\s+href=[^>]+>/g"), "");
                            pm.content = PublishedIndex.Replace("@pagename@", Uri.Join("pages", ThemeYoshi.DefaultPageName + ".html"));
                            pm.partitionKey = "../";
                            pm.rowKey = "index.html";
                        })
                    .AddAw(FileBlobBase.StoreBlobStringAw, (Dictionary) (object) pm)
                    .AddDx(delegate { Inform.Event(fnarg, pm.rowKey);})
                    ;
            }
            awx.Commit(awp);
        }


        private static void DeletePublishedFilesAw(Await awp)
        {
            new Await()
                .AddAw(FileBlobBase.EmptyFolderAw, "../pages")
                .HandleDl(Exceptions.BlobLoadError, Await.IgnoreAw)
                .Commit(awp);
        }

        private static void SnapshotSoftwareAw(Await awp)
        {
            string url = Uri.AddPair(Uri.App("publish.php"), "password", (string)Storage.GetLocal(ThemeYoshi.CuratePasswordKey));
            new Await()
                .LoadJson("snapshot", url)
                .HandleDl(Exceptions.BlobLoadError, Await.IgnoreAw)
                .Commit(awp);
        }
    }
}